package com.chen10.gobang.common.utils;

import com.chen10.gobang.common.constants.TokenTimeConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

public class JwtUtil {

    // TOKEN的有效期一天（S）

    private static final long TOKEN_TIME_OUT = TokenTimeConstants.ONE_WEEK;
    public static final int TOKEN_TIME_OUT_SECOND = 60 * 60 * 24;
    // 加密KEY
    private static final String TOKEN_ENCRYPT_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
    // 最小刷新间隔(S)
    private static final int REFRESH_TIME = 300;


    // 生产ID
    public static String getToken(Integer userId) {
//        Map<String, Object> claimMaps = new HashMap<>();
//        claimMaps.put("id",id);
        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                //header
                .setHeaderParam("typ", "JWT") //类型
                .setHeaderParam("alg", "HS256") //加密算法
                //payload 载荷
                .setId(UUID.randomUUID().toString())
                .claim("userId", userId)
                //.addClaims(claimMaps) //cla信息
                .setSubject("system")  //主题
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT))  //过期时间戳
                //signature 签名
                .signWith(SignatureAlgorithm.HS256, TOKEN_ENCRYPT_KEY) //签发算法
                .setIssuer("chen10") //签发者信息
                .setIssuedAt(new Date(currentTime))  //签发时间
                .compact();
    }

    /**
     * 获取token中的claims信息
     *
     * @param token
     * @return
     */
    public static Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(TOKEN_ENCRYPT_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 获取payload body信息
     *
     * @param token
     * @return
     */
    public static Map<String, Object> getPayloadBodyFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims;
    }

    /**
     * 获取header body信息
     *
     * @param token
     * @return
     */

    public static Map<String, Object> getHeaderBodyFromToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser()
                .setSigningKey(TOKEN_ENCRYPT_KEY)
                .parseClaimsJws(token);
        return claimsJws.getHeader();
    }

    /**
     * 验证token
     *
     * @param token JWT Token
     * @return 是否有效
     */
    public static boolean verifyToken(String token) {
        try {
            Jwts.parser()
                    .setSigningKey(TOKEN_ENCRYPT_KEY)
                    .parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            // If an exception is thrown, the token is not valid.
            return false;
        }
    }

    /**
     * 检查token是否过期
     *
     * @param token JWT Token
     * @return 是否过期
     */
    public static boolean isTokenExpired(String token) {
        Claims claims = getClaimsFromToken(token);
        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }

    /**
     * 从Token中获取用户ID
     *
     * @param token JWT Token
     * @return 用户ID
     */
    public static Integer getUserIdFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        Object userIdObject = claims.get("userId");
        return (Integer) userIdObject;
    }


    /**
     * 获取token距离过期的时间，单位为秒
     *
     * @param token JWT Token
     * @return 距离过期的时间（秒）
     */
    public static long getTokenRemainingTime(String token) {
        Claims claims = getClaimsFromToken(token);
        Date expiration = claims.getExpiration();
        Date now = new Date();
        // 计算剩余时间，单位为毫秒，然后转换成秒
        long remainingTimeInSeconds = (expiration.getTime() - now.getTime()) / 1000;
        return remainingTimeInSeconds > 0 ? remainingTimeInSeconds : 0;
    }


    /**
     * 延长token有效期一天
     *
     * @param token 未过期的JWT Token
     * @return 新的JWT Token
     */
    public static String refreshToken(String token) {
        // 首先验证token是否有效且未过期
        if (!verifyToken(token) || isTokenExpired(token)) {
            throw new IllegalArgumentException("Token is invalid or expired.");
        }

        Claims claims = getClaimsFromToken(token);
        Date originalExpiration = claims.getExpiration();
        long currentTimeMillis = System.currentTimeMillis();

        // 检查是否超过了最小刷新间隔
        if (originalExpiration.getTime() - currentTimeMillis < REFRESH_TIME * 1000) {
            throw new IllegalStateException("Token can not be refreshed within the minimum refresh interval.");
        }

        // 在原有过期时间上增加一天
        Date newExpiration = new Date(originalExpiration.getTime() + TOKEN_TIME_OUT);

        // 使用原有claims创建新的token
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setId(UUID.randomUUID().toString())
                .setClaims(claims) // 使用原有的claims
                .setSubject(claims.getSubject())
                .setExpiration(newExpiration)
                .signWith(SignatureAlgorithm.HS256, TOKEN_ENCRYPT_KEY)
                .setIssuer("chen10")
                .setIssuedAt(new Date(currentTimeMillis))
                .compact();
    }
}
